#[cfg(test)]
pub mod test_ownership {
    use super::dowenership;

    #[test]
    fn towner() {
        dowenership();
    }
}
pub fn dowenership() {

    /* 所有权: rust 独有， 无需GC即可保证内存安全
      1. 每个值都有一个变量， 此变量为这个值的所有者
      2. 每个值同时只能有一个所有者
      3. 当所有者超出作用域(scope), 该值被删除
     */
    

    /* 字符串
    1. 字面值: 编译是就知道， 速度快 高效 不可变
    2. 可变值： 分配在 heap 上
        - 运行时请求内存， 调用String::from
        - 用完后， 需要释放
            - rust是没有gc的语言， 就要去识别何时不用， 并调用代码释放
            - 如果忘了 会浪费内存
            - 提前做了， 变量会不可用
            - 做了两次 bug， 必须一次分配一次释放
     */
    let mut hello = String::from("hello");
    hello.push_str(" world!");
    println!("hello = {}", hello);

    let hello1 = hello;
    // 这里hello指向的值 被赋值给hello1， 所以hello将不可访问
    // println!("hello 2 = {}", hello);
    println!("hello1 = {}", hello1);


    // rust 如果某个值的拥有者走出作用域, 这个值会被立刻释放, drop函数

    // 变量和数据的交互（Move）:
    // 1. 基础类型: int是固定长度的类型， 两个5 都会被压到栈中
    let int1 = 5;
    let int2 = int1;
    println!("int1 = {}; int2 = {}", int1, int2);
    // 2. String
    // s1 在栈中值类似这样 -> [s1_ptr(指向存值的heap地址), s1_len, s1_capacity]
    let s1 = String::from("This is string value");
    // s2 -> [s1_ptr, s2_len, s2_capacity], 值的所有权变成了s2， 所以s1 将不可访问
    // 这里复制了sq 的指针 长度 容量， 但没有重新复制一份数据
    let s2 = s1; // 浅拷贝
    // 当s1 s2 离开作用域时， s1 s2 都会尝试释放相同的heap数据， 两次释放会存在bug
    // 为了内存安全， rust 会让s1失效， 这里用一个新术语 -- 移动(Move)
    // println!("s1 = {}", s1);
    println!("s2 = {}", s2);
    let s3 = s2.clone(); // 深拷贝
    println!("s3 = {}", s3);

    /* Stack上的数据: 复制
    - copy trait(特质), 可以用于放在堆上的基础数据类型
    - 如果一个类型实现了 Copy trait, 那么在赋值后 原变量还能用
        - 简单的类型、组合都是Copy的
        - 需要分配内存的都不是Copy的
        - 拥有Copy的类型: 
            - 所有整数型
            - 所有浮点型
            - bool
            - char
            - tuple(元组): 需要 其所有字段都是Copy的, (i32, u32)是， (u32, String)则不是
    - 如果一个类型 或 类型的一部分 实现了 Drop trait, 那 rust 不允许再实现 Copy trait
     */


    /*
    将值传递给函数 与赋值类似， 会发生所有权转移， 复制和移动
     */
    let m_str = String::from("str");
    move_str(m_str);
    // println!("m_str = {}", m_str); // 传递给函数 发生了 move, 此变量已经不可用    

    let m_i = 61;
    move_int(m_i);
    println!("m_i = {}", m_i);

    // 函数返回值 也会发生所有权转移
    let mr_str1 = move_return_str();
    let mr_str2 = String::from("m_str2 value");
    let mr_str3 = move_return_str2(mr_str2);
    println!("mr_str1 = {}", mr_str1);
    // println!("mr_str2 = {}", mr_str2);
    println!("mr_str3 = {}", mr_str3);

    /*
    变量所有权总是遵循相同的模式
    把一个值赋值给其他变量就会发生移动
    当包含heap的变量离开作用域时， 就会调用drop函数清理, 除非所有权转移到另一个变量
     */

     {
        println!(" --------- calc -> () ------------- ");
        let s = String::from("calc string value");
        let (s1, len) = calc_len(s);
        // print!("s = {}", s);
        println!("s1 = {}; len = {}", s1, len);
    }

}


fn move_str(s: String) {
    println!("move_str -> {}", s);
}

fn move_int(i: i32) {
    println!("move_int -> {}", i);
}

fn move_return_str() -> String {
    let s = String::from("move_return_str <- value");
    s
}
fn move_return_str2(s: String) -> String {
    println!("move_return_str2 -> {}", s);
    s
}

fn calc_len(s: String) -> (String, usize) {
    let len = s.len();
    (s, len)
}
